package br.com.ps.bombertournament.game;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

/**
 * Contains all objects must be rendered on the scene
 * 
 * @author Rennan Stefan Boni - rennanboni@gmail.com
 */
public class Layer implements GameObject {
	
	private int priority;
	
	private List<BaseGameObject> queueRender;
	private List<BaseGameObject> addQueueRender;
	private List<BaseGameObject> removeQueueRender;
	
	private Comparator<BaseGameObject> comparator = new Perpective2D();
	
	public Layer(Game game, int initialCapacity, int priority) {
		queueRender = new ArrayList<BaseGameObject>(initialCapacity);
		addQueueRender = new ArrayList<BaseGameObject>(initialCapacity);
		removeQueueRender = new ArrayList<BaseGameObject>(initialCapacity);
		
		this.priority = priority;
	}
	
	public Layer(Game game, int initialCapacity) {
		queueRender = new ArrayList<BaseGameObject>(initialCapacity);
		addQueueRender = new ArrayList<BaseGameObject>(initialCapacity);
		removeQueueRender = new ArrayList<BaseGameObject>(initialCapacity);
	}
	
	public Layer(Game game) {
		this(game, 10);
	}
	
	/**
	 * Render all objects in the list
	 * 
	 * @param spriteBatch Local where will be rendered the game objects
	 */
	public void render(SpriteBatch spriteBatch) {
		if (queueRender != null) {
			for (BaseGameObject renderable : queueRender) {
				renderable.render(spriteBatch);
			}
		}
	}
	
	
	/**
	 * Add new game object on the list render
	 * 
	 * @param gameObject New game object
	 * @return Return true if the game object was added, otherwise return false
	 */
	public boolean add(BaseGameObject gameObject) {
		boolean result = false;
		
		if (gameObject != null) {
			result = addQueueRender.add(gameObject);
			gameObject.setLayer(this);
		}
		
		return result;
	}
	
	/**
	 * remove the game object on the list render
	 * 
	 * @param gameObject The game object will be removed on the list render
	 * @return  Return true if the game object was removed, otherwise return false
	 */
	public boolean remove(BaseGameObject gameObject) {
		return removeQueueRender.add(gameObject);
	}

	/**
	 * Dispose the layer and all game object on the list render
	 */
	public void dispose() {
		if (queueRender != null) {
			for (BaseGameObject renderable : queueRender) {
				renderable.dispose();
			}
		}
	}

	/**
	 * Update the Layer.
	 * <br> Add/Remove all pending items on the root render list and call the update method all game object
	 * 
	 * @param deltaTime The delta time value
	 */
	public void update(float deltaTime) {
		if (queueRender != null) {
			
			// Adicionando na lista o objetos pendentes
			addPending();
			
			// Removendo na lista o objetos pendentes
			removePending();
			
			for (BaseGameObject renderable : queueRender) {
				renderable.update(Gdx.graphics.getDeltaTime());
			}
			
			Collections.sort(queueRender, comparator);
		}
	}

	/**
	 * Find the game object with a specific id
	 * 
	 * @param id The id value who is looking for
	 * @return Return the game object founded, can return null.
	 */
	public BaseGameObject findObjectById(String id) {
		BaseGameObject result = null;
		
		if (queueRender != null) {
			for (BaseGameObject renderable : queueRender) {
				result = renderable.getId() != null && id.equals(renderable.getId()) ? renderable : null;
				
				if (result != null) {
					break;
				}
			}
		}
		
		return result;
	}

	/**
	 * Add pending game object on the root render list
	 */
	public void addPending() {
		// Adicionando na lista o objetos pendentes
		for (BaseGameObject gameObject : addQueueRender) {
			queueRender.add(gameObject);
		}
		
		addQueueRender.clear();
	}
	
	/**
	 * Remove pending game object on the root render list
	 */
	private void removePending() {
		// Removendo na lista o objetos pendentes
		for (BaseGameObject gameObject : removeQueueRender) {
			queueRender.remove(gameObject);
			gameObject.onRemove();
			gameObject.setLayer(null);
		}
		
		removeQueueRender.clear();
	}

	/**
	 * Return the render list of the layer
	 * 
	 * @return Return a list of game object
	 */
	public List<BaseGameObject> getQueueRender() {
		return queueRender;
	}

	/**
	 * Return the priority of the Layer
	 * 
	 * @return Return the priority of the Layer
	 */
	public int getPriority() {
		return priority;
	}

}
